#include "types/common.h"
#include "modules/buffer_mgr.h"
#include "types/record.h"
#include "types/bpnode.h"
#include "types/errors.h"

#ifndef _bptree_h_
#define _bptree_h_

class bptree
{
public:
	//The constructor will have two overloaded variants
	
	//This would load an existing B+tree from file.
	//Will detect if duplicate is supported or not from the file header
	bptree(string name);
	bptree(string name, bool dupAllowed,  vector<index_data> keys = vector<index_data>()); 


	int RecInsert(struct index_data data); 
	bool update(index_data data); 

	vector<index_data> lookup(Condition cond) ; //return value is a vector to support duplicates
	vector<index_data> lookup(UINT32 key) ; //return value is a vector to support duplicates
	
	void print(string what);
	
	inline bool isDupAllowed() 
	{
		if(header.dupAllowed)
			return true;
		else
			return false;
	}
	
	static bool index_debug;
private:
	//Needs to be called only on an empty tree
	bool bulk_insert(vector<index_data> keys);

	//Internal B-Tree Algorithm
	void Lookup(long Key,struct index_entry *Node,UINT32 lookUpFlag);
	int checkIfOvwFlowExists(struct data_entry *Node,UINT32 key);
	vector<index_data> searchLessThan(UINT32 key);
	int FindKey(struct data_entry *Node, UINT32 Key); 
	vector<index_data> searchGreaterThan(UINT32 key);
	vector<index_data> searchRange(UINT32 key1,UINT32 key2);
	vector<index_data> search(UINT32 key);
	void bpPrintNode(struct index_entry *Node);
	void bpPrint();
	int redistribute(struct data_entry *Node, UINT32 KIdx, struct index_data data);
	int InsertKeyOnLeaf(struct data_entry *Node, UINT32 KIdx,
			struct index_data data,UINT32 *Key, UINT32 *Ptr,UINT32 *blockNum); 
	int InsertKeyOnNonLeaf(struct index_entry *Node, UINT32 KIdx, 
			UINT32 *Key, UINT32 *Ptr,UINT32 *blockNum); 
	void HandleDup(struct data_entry *Node, struct index_data &data,
			UINT32 keyIndex,UINT32 blockNum);

	//Header of the file, to be initialized at the time of constructor
	struct index_header header;
	string indexName;
	//Cache Block
	MemoryCache cache[10];//Instead of Stack, the records are copied onto cacheBlock
	BYTE cacheId;
	BufferManager &bm;
	void read_block(string &tblname, UINT32 block_num, BYTE *data);
	void write_block(string &tblname, UINT32 block_num, BYTE *data);	
};
#endif
